package net.borderwars.webstartclient;

import net.borderwars.beans.Player;
import net.borderwars.beans.Robot;
import net.borderwars.userserver.ServerInterface;
import net.borderwars.vm.VMState;
import net.borderwars.vm.VirtualMachine;
import org.apache.bcel.generic.Instruction;

import javax.swing.*;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.Semaphore;

/**
 * @author hubbard
 *         Date: May 12, 2006
 *         Time: 1:40:45 PM
 */
public class BattleThread extends Thread {
    private Battle battle;
    private ServerInterface server;
    private Player player;
    private LinkedList<Robot> bots;
    private HashSet<Robot> badGuys = new HashSet<Robot> ();

    public void setSleep (final long sleep) {
        this.sleep = sleep;
    }

    private volatile long sleep = 0;

    private HashMap<Robot, VirtualMachine> machines = new HashMap<Robot, VirtualMachine> ();

    public BattleThread (Battle battle, ServerInterface server, Player player, LinkedList<Robot> bots) {
        this.battle = battle;
        this.server = server;
        this.player = player;
        this.bots = bots;
        start ();
    }

    volatile boolean done = false;
    volatile boolean pause = false;
    Semaphore sem;

    public int getSourceLineNumber (Robot r) {
        VirtualMachine vm = machines.get (r);
        return (vm.getSourceLineNumber ());
    }

    public void tick () {
        sem.release (bots.size ());
    }

    public void run () {
        createVirtualMachines ();

        // main loop
        while (!done) {
            for (Map.Entry<Robot, VirtualMachine> bot : machines.entrySet ()) {
                if (pause) {
                    try {
                        sem.acquire ();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace ();
                    }
                }
                if (sleep != 0) {
                    try {
                        Thread.sleep (sleep);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace ();  //To change body of catch statement use File | Settings | File Templates.
                    }
                }
                Robot robot = bot.getKey ();
                VirtualMachine vm = bot.getValue ();

                try {
                    if (!badGuys.contains (robot)) {
                        vm.tick ();
                        state = vm.getState ();
                        battle.updateData (); // update the battlefield GUI
                    }
                }
                catch (Throwable t) {
                    t.printStackTrace ();
                    JOptionPane.showMessageDialog (null, t.getStackTrace (), "Error executing BOT", JOptionPane.ERROR_MESSAGE);
                    badGuys.add (robot);
                }
            }
        }

    }

    private void createVirtualMachines () {
        for (Robot robot : bots) {
            byte data[];
            try {
                data = robot.getByteCode ();
                if (data == null) {
                    try {
                        data = server.getBytes (robot);
                    }
                    catch (SQLException e) {
                        e.printStackTrace ();
                    }
                }
                VirtualMachine vm = new VirtualMachine (robot.getName (), data, false);
                machines.put (robot, vm);
            }
            catch (IOException e) {
                e.printStackTrace ();
            }
            catch (InterruptedException e) {
                e.printStackTrace ();
            }
        }
    }

    private VMState state;

    public TreeMap<Integer, Instruction> getCurrentInstructions (Robot selectedBot) {
        if (state == null) {
            VirtualMachine vm = machines.get (selectedBot);
            state = vm.getState ();
        }
        return (state.getCurrentMethod ().getInstructions ());
    }

    public int getCurrentIndex (final Robot selectedBot) {
        if (state == null) {
            VirtualMachine vm = machines.get (selectedBot);
            state = vm.getState ();
        }
        return (state.getCurrentPC ());
    }

    public void setPause (final boolean paused) {
        if (paused) {
            sem = new Semaphore (0);
        }
        this.pause = paused;
    }
}
